Monitor = class("Monitor")

Monitor.profilingFileName = gRootPath .. "profiling.out"

---

function Monitor:initialize(profilling)

	gMonitor = self
	self.profilling = profilling
	
	if profilling then
	
		package.cpath = package.cpath .. ";C:\\Program Files (x86)\\Lua\\5.1\\clibs\\?.dll"
		require ("profiler")
	end

end

function Monitor:onBeatStart()

	if self.profilling then
	
		profiler.start(Monitor.profilingFileName)
	end
end

---

function Monitor:onBeatEnd()
	
	if self.profilling then
	
		profiler.stop()
	end
end

---

function Monitor:onApplicationExit()

	if self.profilling then
	
		self:displayProfileSummary()
	end
end

---

function Monitor:displayProfileSummary()
	
	self:readProfileFile()
	self:createProfileSummary()

	local sortedSumary = {}
	
	for k, v in pairs(self.summary) do
	 
		table.insert(sortedSumary, v) 
	end
	
	table.sort(
		sortedSumary, 
		function (a, b)
		 
			return tonumber(a["info"]["total"]) > tonumber(b["info"]["total"]) 
		end
	)
	
	print("\n\nProfiling results :\n")
	self:displayProfileSummaryLine({"Module name","Function name","Calls","Average per call","Total time","%Time"})
	print("---")
	
	for k, line in pairs(sortedSumary) do
	
		if line["info"]["func"] ~= "(null)" then
		
			local average = line["info"]["total"] / line["info"]["calls"]
			local percent = 100 * line["info"]["total"] / self.globalTime
			
		 	self:displayProfileSummaryLine(
			 	{
			 		line["info"]["module"], 
			 		line["info"]["func"], 
			 		line["info"]["calls"], 
			 		average, 
			 		line["info"]["total"], 
			 		percent
			 	}
			 )
		end
	end
end

---

function Monitor:displayProfileSummaryLine(entries)

	local line = ""
	local tabs = {30,30,15,15,15,15}
	
	for i, entry in ipairs(entries) do
	
		if type(entry) == "number" then
		
			entry = string.format("%.3f", entry)
		end
		
		local spacing = ""
		
		for space = 0, tabs[i] - string.len(entry) do 
			
			spacing = spacing .. "_" 
		end
		
		line = line .. entry .. spacing .. "\t"
	end
	
	print(line)
end

---

function Monitor:readProfileFile()

	local profile = io.open(Monitor.profilingFileName)
	local i = 1
		
	self.lineBuffer = {}
	
	for line in profile:lines() do
	
		self.lineBuffer[i] = line
		i = i + 1
    end

	profile:close()
end

---

function Monitor:createProfileSummary()

	local localTime
	local totalTime

	self.globalTime = 0
	self.summary = {}
	
	for i = 1, table.getn(self.lineBuffer) do
	
		local module = string.match(self.lineBuffer[i], "[^\t]+\t([^\t]+)")
		local func = string.match(self.lineBuffer[i], "[^\t]+\t[^\t]+\t([^\t]+)")
		local key = module .. func
		
		localTime, totalTime = string.match(
			self.lineBuffer[i], 
			"[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+\t([^\t]+)\t([^\t]+)"
		)
		
        if 
        	localTime and 
        	totalTime and
        	(localTime ~= "local_time")
        then
        
	        if self.summary[key] == nil then
	        
				self.summary[key] = {};
				self.summary[key]["info"] = {}
				self.summary[key]["info"]["calls"] = 1
				self.summary[key]["info"]["total"] = localTime
				self.summary[key]["info"]["module"] = module
				self.summary[key]["info"]["func"] = func
			else
				self.summary[key]["info"]["calls"] = self.summary[key]["info"]["calls"] + 1
				self.summary[key]["info"]["total"] = self.summary[key]["info"]["total"] + localTime;
			end
	
			self.globalTime = self.globalTime + localTime;
		end
	end
end

